﻿using Microsoft.AspNetCore.SignalR.Client;

using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;

using PLCS.App.Shared.Events;
using PLCS.App.Shared.Models;
using PLCS.App.Shared.Views.UserControls.Chlidren;
using PLCS.Client.Service.Client;
using PLCS.Domain.Shared.Enums;
using PLCS.Shared.Common.Constant;
using PLCS.Shared.Common.Extensions;
using PLCS.Shared.Common.Helper;

using System.IO;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Xml.Serialization;

using Station = PLCS.App.Shared.Views.UserControls.Chlidren.Station;

namespace PLCS.App.Shared.Views.UserControls;

/// <summary>
/// FrameControl.xaml 的交互逻辑
/// </summary>
public partial class FrameControl : UserControl
{
    #region Properties

    private IEventAggregator _eventAggregator;

    private HubConnection hubConnection;
    private Frame_Config CADFrame;
    private double ratio;//系数、比例
    private double trackratio;//轨道比例
    private DispatcherTimer dpTimer;
    public HttpRestClient restClient = new HttpRestClient();
    private Timer timer;

    public string ConfigUrl
    {
        get { return (string)GetValue(ConfigUrlProperty); }
        set { SetValue(ConfigUrlProperty, value); }
    }

    // Using a DependencyProperty as the backing store for ConfigUrl.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ConfigUrlProperty =
        DependencyProperty.Register("ConfigUrl", typeof(string), typeof(FrameControl));

    /// <summary>
    /// 固定的边
    /// </summary>
    public FixedSideEnum FixedSide
    {
        get { return (FixedSideEnum)GetValue(FixedSideProperty); }
        set { SetValue(FixedSideProperty, value); }
    }

    // Using a DependencyProperty as the backing store for FixedSide.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty FixedSideProperty =
        DependencyProperty.Register("FixedSide", typeof(FixedSideEnum), typeof(FrameControl), new PropertyMetadata(FixedSideEnum.Height));

    public MapMode MapMode
    {
        get { return (MapMode)GetValue(MapModeProperty); }
        set { SetValue(MapModeProperty, value); }
    }

    // Using a DependencyProperty as the backing store for MapMode.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty MapModeProperty =
        DependencyProperty.Register("MapMode", typeof(MapMode), typeof(FrameControl), new PropertyMetadata(MapMode.Default));

    /// <summary>
    /// 元素点击事件
    /// </summary>
    public ICommand FrameCommand
    {
        get { return (ICommand)GetValue(FrameCommandProperty); }
        set { SetValue(FrameCommandProperty, value); }
    }

    // Using a DependencyProperty as the backing store for ItemCommand.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty FrameCommandProperty =
        DependencyProperty.Register("FrameCommand", typeof(ICommand), typeof(FrameControl));

    /// <summary>
    /// 元素点击事件参数
    /// </summary>
    public object FrameCommandParameter
    {
        get { return (object)GetValue(FrameCommandParameterProperty); }
        set { SetValue(FrameCommandParameterProperty, value); }
    }

    // Using a DependencyProperty as the backing store for ItemCommandParameter.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty FrameCommandParameterProperty =
        DependencyProperty.Register("FrameCommandParameter", typeof(object), typeof(FrameControl));

    private int SizeChnangedCount = 0;

    #endregion Properties

    #region Contructor

    public FrameControl()
    {
        InitializeComponent();
        InitalHub();
        _eventAggregator = ContainerLocator.Container.Resolve<IEventAggregator>();

    

        _eventAggregator.GetEvent<SaveEvent>().Subscribe(async () => await InitFrame());
        SizeChanged += async (o, e) => await InitFrame();

        dpTimer = new DispatcherTimer();
        dpTimer.Start();
        SizeChanged += FrameControl_SizeChanged;
       

    }

   

   
    TextBlock textBlock = new TextBlock();
    
    private void FrameControl_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        
        //textBlock.FontSize = 50;
        //textBlock.Text = "sssssss";
        //Canvas.SetLeft(textBlock,1500);
        //Canvas.SetTop(textBlock,150);
        //frame.Children.Add(textBlock);
        //StaticClass.Run();

    }

    #endregion Contructor

    #region Method

    private void InitalHub()
    {
        hubConnection = new HubConnectionBuilder().WithUrl(AddressManager.Address + AddressManager.FrameHub).Build();
        hubConnection.On<string, YesNo>("ChangeStationStatus", async (sname, status) =>
        {
            await System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
            {
                if (frame.FindName(sname) is Station station)
                {
                    if (status != station.HaveStatus)
                        station.HaveStatus = status;
                }
                else if (frame.FindName(sname) is ConveyorLine conveyorLine)
                {
                    if (status != conveyorLine.HaveStatus)
                        conveyorLine.HaveStatus = status;
                }
                else if (frame.FindName(sname) is RotaryTable rotaryTable)
                {
                    if (status != rotaryTable.HaveStatus)
                        rotaryTable.HaveStatus = status;
                }
                else if (frame.FindName(sname) is Pipeline pipeline)
                {
                    pipeline.tray.Visibility = status == YesNo.是 ? Visibility.Visible : Visibility.Collapsed;
                }
            }), System.Windows.Threading.DispatcherPriority.Send);
        });
        hubConnection.On<string, DeviceStatus>("ChangeEquipmentStatus", async (name, status) =>
        {
            await System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
            {
                if (frame.FindName(name) is RGV rgv)
                {
                    //设备状态颜色变化
                    switch (status)
                    {
                        case DeviceStatus.空闲:
                            rgv.statusLeft.Background = Brushes.DimGray;
                            rgv.statusRight.Background = Brushes.DimGray;
                            break;

                        case DeviceStatus.忙碌:
                            rgv.statusLeft.Background = new SolidColorBrush(Color.FromRgb(0, 230, 118));// "#ABFF33";
                            rgv.statusRight.Background = new SolidColorBrush(Color.FromRgb(0, 230, 118));// "#ABFF33";
                            //rgv.bg = new SolidColorBrush(Color.FromRgb(0, 230, 118));// "#ABFF33";
                            break;

                        case DeviceStatus.故障:
                            rgv.statusLeft.Background = new SolidColorBrush(Color.FromRgb(255, 61, 0));
                            rgv.statusRight.Background = new SolidColorBrush(Color.FromRgb(255, 61, 0));
                            //rgv.bg = new SolidColorBrush(Color.FromRgb(255, 61, 0));
                            break;

                        case DeviceStatus.未知:
                            rgv.statusLeft.Background = Brushes.DimGray;
                            rgv.statusRight.Background = Brushes.DimGray;
                            //rgv.bg = Brushes.DimGray;
                            break;

                        case DeviceStatus.暂停:
                            rgv.statusLeft.Background = new SolidColorBrush(Color.FromRgb(255, 61, 0));
                            rgv.statusRight.Background = new SolidColorBrush(Color.FromRgb(255, 61, 0));
                            //rgv.bg = new SolidColorBrush(Color.FromRgb(255, 61, 0));
                            break;

                        default:
                            rgv.bg = Brushes.Transparent;
                            break;
                    }
                    //if (rgv.Background.ToString() != rgv.bg.ToString())
                    //{
                    //    rgv.Background = rgv.bg;
                    //    //边框颜色变化
                    //    rgv.bottomline.Fill = rgv.topline.Fill = rgv.rightline.Fill = rgv.leftline.Fill = Background == Brushes.Transparent ? Brushes.Gray : rgv.Background;
                    //}
                }
                else if (frame.FindName(name) is Stacker stacker)
                {
                    //设备状态颜色变化
                    switch (status)
                    {
                        case DeviceStatus.空闲:
                            stacker.statusLeft.Background = Brushes.DimGray;
                            stacker.statusRight.Background = Brushes.DimGray;
                            break;

                        case DeviceStatus.忙碌:
                            stacker.statusLeft.Background = new SolidColorBrush(Color.FromRgb(0, 230, 118));// "#ABFF33";
                            stacker.statusRight.Background = new SolidColorBrush(Color.FromRgb(0, 230, 118));// "#ABFF33";
                            break;

                        case DeviceStatus.故障:
                            stacker.statusLeft.Background = new SolidColorBrush(Color.FromRgb(255, 61, 0));
                            stacker.statusRight.Background = new SolidColorBrush(Color.FromRgb(255, 61, 0));
                            break;

                        case DeviceStatus.未知:
                            stacker.statusLeft.Background = Brushes.DimGray;
                            stacker.statusRight.Background = Brushes.DimGray;
                            break;

                        case DeviceStatus.暂停:
                            stacker.statusLeft.Background = new SolidColorBrush(Color.FromRgb(255, 61, 0));
                            stacker.statusRight.Background = new SolidColorBrush(Color.FromRgb(255, 61, 0));
                            break;

                        default:
                            stacker.statusLeft.Background = Brushes.Transparent;
                            break;
                    }
                }
                else if (frame.FindName(name) is ConveyorLine conveyorLine)
                {
                    //设备状态颜色变化
                    switch (status)
                    {
                        case DeviceStatus.空闲:
                            conveyorLine.bg = Brushes.DimGray;
                            break;

                        case DeviceStatus.忙碌:
                            conveyorLine.bg = new SolidColorBrush(Color.FromRgb(0, 230, 118));// "#ABFF33";
                            break;

                        case DeviceStatus.故障:
                            conveyorLine.bg = new SolidColorBrush(Color.FromRgb(255, 61, 0));
                            break;

                        case DeviceStatus.未知:
                            conveyorLine.bg = Brushes.DimGray;
                            break;

                        case DeviceStatus.暂停:
                            conveyorLine.bg = new SolidColorBrush(Color.FromRgb(255, 61, 0));
                            break;

                        default:
                            conveyorLine.bg = Brushes.Transparent;
                            break;
                    }
                    if (conveyorLine.Background.ToString() != conveyorLine.bg.ToString())
                    {
                        conveyorLine.Background = conveyorLine.bg;
                        //边框颜色变化
                        conveyorLine.bottomline.Fill = conveyorLine.topline.Fill = conveyorLine.rightline.Fill = conveyorLine.leftline.Fill = Background == Brushes.Transparent ? Brushes.Gray : conveyorLine.Background;
                    }
                }
            }));
        });

        hubConnection.On<string, string>("ChangeEquipmentLocation", async (name, stationName) =>
        {
            await System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
            {
                RGV rgv = frame.FindName(name) as RGV;
                if (rgv != null)
                {
                    rgv.MoveAnimation(stationName);
                }
            }));
        });

        hubConnection.On<int>("ChangeErrorLogCount", (count) =>
        {
            _eventAggregator.GetEvent<ErrorLogCountEvent>().Publish(count);
        });
        hubConnection.On<string, string, string>("ChangeCranePosition", async (equipmentNo, rowGoodNo, column) =>
        {
            await System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() =>
            {
                Stacker rgv = frame.FindName(equipmentNo) as Stacker;
                if (rgv != null)
                {
                    rgv.CraneMoveAnimation(rowGoodNo, column);
                }
            }));
        });
    }

    /// <summary>
    /// 新修改 初始化
    /// </summary>
    /// <param name="fileName"></param>
    public async Task InitFrame()
    {
        string fileName = ModelConfigManager.ModelConfigPath;
        SizeChnangedCount++;
        if (SizeChnangedCount == 2)
            return;
        if (!File.Exists(fileName))
        {
            return;
        }
        var tablewh = TableHelper.ExcelToTable(fileName, 1);
        if (tablewh == null) return;
        if (tablewh.Rows.Count == 0) return;
        double cadw = double.Parse($"{tablewh.Rows[0]["CadW"]?.ToString()}");
        double cadh = double.Parse($"{tablewh.Rows[0]["CadH"]?.ToString()}");
        frame.Children.Clear();

        switch (FixedSide)
        {
            case FixedSideEnum.Height:
                frame.Height = RenderSize.Height;
                switch (MapMode)
                {
                    case MapMode.Default:
                        frame.Width = (cadw * frame.Height) / cadh;
                        ratio = frame.Height / cadh;
                        break;

                    case MapMode.Overturn:
                        frame.Width = (cadh * frame.Height) / cadw;
                        ratio = frame.Height / cadw;
                        break;

                    default:
                        break;
                }
                break;

            case FixedSideEnum.Width:
                frame.Width = RenderSize.Width;
                switch (MapMode)
                {
                    case MapMode.Default:

                        frame.Height = (cadh * frame.Width) / cadw;
                        ratio = frame.Height / cadh;
                        break;

                    case MapMode.Overturn:
                        frame.Height = (cadw * frame.Width) / cadh;
                        ratio = frame.Height / cadw;
                        break;

                    default:
                        break;
                }

                break;

            default:
                break;
        }

        #region 添加元素
       
        var table = TableHelper.ExcelToTable(fileName);
        var modelConfigs = table.ToList<ModelControl>();
        foreach (var row in modelConfigs)
        {
            await Dispatcher.BeginInvoke(() =>
            {
                var control = new UIElement();
                string controlstyle = row.ControlStyle;
                //control
                switch (controlstyle)
                {
                    case "VirtualStation":
                        break;
                    //货位
                    case "RowGoods":
                        RowGoods rowGoods = new RowGoods()
                        {
                            SName = $"{row.SName ?? "W101"}",
                            Width = Convert.ToDouble(row.Width) * ratio,
                            Height = Convert.ToDouble(row.Height) * ratio,
                            ColumnCount = Convert.ToInt32(row.ColumnCount),
                            NoDisplayColumn = row.NoDisplayColumn,
                            Roadway = Convert.ToInt32(row.Roadway),
                            LayerCount = Convert.ToInt32(row.LayerCount),
                            Platepos = row.Platepos,
                            Row = Convert.ToInt32(row.Row),
                            Command = FrameCommand,
                            CommandParameter = $"{controlstyle}-{row.Roadway}，{row.Row}，{row.ColumnCount}，{row.LayerCount}，{row.Platepos}"
                        };

                        switch (MapMode)
                        {
                            case MapMode.Default:
                                Canvas.SetLeft(rowGoods, Convert.ToDouble(row.X) * ratio);
                                Canvas.SetTop(rowGoods, Convert.ToDouble(row.Y) * ratio);
                                break;

                            case MapMode.Overturn:
                                Canvas.SetLeft(rowGoods, Convert.ToDouble(row.Y) * ratio);
                                Canvas.SetTop(rowGoods, Convert.ToDouble(row.X) * ratio);
                                break;

                            default:
                                break;
                        }
                        frame.Children.Add(rowGoods);
                        RegisterName(frame, $"{rowGoods.SName}", rowGoods);
                        break;
                    //工位
                    case "Station":
                        Station station = new()
                        {
                            BorderThickness = new Thickness(0),
                            Background = Brushes.DimGray,
                            SName = $"{row.SName ?? "W101"}",
                            Name = $"{row.SName ?? "W101"}",
                            Width = Convert.ToDouble(row.Width) * ratio,
                            Height = Convert.ToDouble(row.Height) * ratio,
                            Command = FrameCommand,
                            CommandParameter = $"{controlstyle}-{row.SName ?? "W101"}",
                        };
                        switch (MapMode)
                        {
                            case MapMode.Default:
                                Canvas.SetLeft(station, Convert.ToDouble(row.X) * ratio);
                                Canvas.SetTop(station, Convert.ToDouble(row.Y) * ratio);
                                break;

                            case MapMode.Overturn:
                                Canvas.SetLeft(station, Convert.ToDouble(row.Y) * ratio);
                                Canvas.SetTop(station, Convert.ToDouble(row.X) * ratio);
                                break;

                            default:
                                break;
                        }
                        frame.Children.Add(station);
                        RegisterName(frame, station.SName, station);
                        //frame.RegisterName($"{station.SName}", station);
                        break;
                    //输送线
                    case "ConveyorLine":
                        ConveyorLine conveyorLine = new()
                        {
                            SName = $"{row.SName ?? "W101"}",
                            Name = $"{row.SName ?? "W101"}",
                            Width = Convert.ToDouble(row.Width) * ratio,
                            Height = Convert.ToDouble(row.Height) * ratio,
                            Command = FrameCommand,
                            CommandParameter = $"{controlstyle}-{row.SName ?? "WC101"}"
                        };
                        switch (MapMode)
                        {
                            case MapMode.Default:
                                Canvas.SetLeft(conveyorLine, Convert.ToDouble(row.X) * ratio);
                                Canvas.SetTop(conveyorLine, Convert.ToDouble(row.Y) * ratio);
                                break;

                            case MapMode.Overturn:
                                Canvas.SetLeft(conveyorLine, Convert.ToDouble(row.Y) * ratio);
                                Canvas.SetTop(conveyorLine, Convert.ToDouble(row.X) * ratio);
                                break;

                            default:
                                break;
                        }
                        frame.Children.Add(conveyorLine);
                        RegisterName(frame, conveyorLine.SName, conveyorLine);
                        break;

                    //输送线
                    case "Pipeline":
                        Pipeline pipeline = new()
                        {
                            StationCount = int.Parse(row.Capacity ?? "6"),
                            SName = $"{row.SName ?? "WP101"}",
                            Name = $"{row.SName ?? "WP101"}",
                            Width = Convert.ToDouble(row.Width) * ratio,
                            Height = Convert.ToDouble(row.Height) * ratio,
                            Command = FrameCommand,
                            CommandParameter = $"{controlstyle}-{row.SName ?? "WP101"}"
                        };
                        switch (MapMode)
                        {
                            case MapMode.Default:
                                Canvas.SetLeft(pipeline, Convert.ToDouble(row.X) * ratio);
                                Canvas.SetTop(pipeline, Convert.ToDouble(row.Y) * ratio);
                                break;

                            case MapMode.Overturn:
                                Canvas.SetLeft(pipeline, Convert.ToDouble(row.Y) * ratio);
                                Canvas.SetTop(pipeline, Convert.ToDouble(row.X) * ratio);
                                break;

                            default:
                                break;
                        }
                        frame.Children.Add(pipeline);
                        RegisterName(frame, pipeline.SName, pipeline);
                        break;

                    case "AgvStation":
                        AgvStation agvStation = new AgvStation()
                        {
                            SName = $"{row.SName ?? "WP101"}",
                            Name = $"{row.SName ?? "WP101"}",
                            Width = Convert.ToDouble(row.Width) * ratio,
                            Height = Convert.ToDouble(row.Height) * ratio,
                            Command = FrameCommand,
                            CommandParameter = $"{controlstyle}-{row.SName ?? "WP101"}"
                        };
                        switch (MapMode)
                        {
                            case MapMode.Default:
                                Canvas.SetLeft(agvStation, Convert.ToDouble(row.X) * ratio);
                                Canvas.SetTop(agvStation, Convert.ToDouble(row.Y) * ratio);
                                break;

                            case MapMode.Overturn:
                                Canvas.SetLeft(agvStation, Convert.ToDouble(row.Y) * ratio);
                                Canvas.SetTop(agvStation, Convert.ToDouble(row.X) * ratio);
                                break;

                            default:
                                break;
                        }
                        frame.Children.Add(agvStation);
                        RegisterName(frame, agvStation.SName, agvStation);
                        //frame.RegisterName($"{agvStation.SName}", agvStation);

                        break;
                    //轨道
                    case "Track":
                        Track track = new Chlidren.Track()
                        {
                            SName = $"{row.SName ?? "WP101"}",
                            Name = $"{row.SName ?? "WP101"}",
                            Width = Convert.ToDouble(row.Width) * ratio,
                            Height = Convert.ToDouble(row.Height) * ratio,
                            PlatePos = row.Platepos
                        };
                        Canvas.SetZIndex(track, -1);
                        // track.PlatePos = row["Platepos"]?.ToString() ?? track.PlatePos;
                        switch (MapMode)
                        {
                            case MapMode.Default:
                                Canvas.SetLeft(track, Convert.ToDouble(row.X) * ratio);
                                Canvas.SetTop(track, Convert.ToDouble(row.Y) * ratio);
                                break;

                            case MapMode.Overturn:
                                Canvas.SetLeft(track, Convert.ToDouble(row.Y) * ratio);
                                Canvas.SetTop(track, Convert.ToDouble(row.X) * ratio);
                                break;

                            default:
                                break;
                        }
                        frame.Children.Add(track);
                        RegisterName(frame, track.SName, track);
                        //track.RegisterName($"{track.SName}", track);

                        break;

                    case "RotaryTable":
                        RotaryTable rotaryTable = new RotaryTable()
                        {
                            SName = $"{row.SName ?? "WP101"}",
                            Name = $"{row.SName ?? "WP101"}",
                            Width = Convert.ToDouble(row.Width) * ratio,
                            Height = Convert.ToDouble(row.Height) * ratio,
                            Command = FrameCommand,
                            CommandParameter = $"{controlstyle}-{row.SName ?? "WP101"}"
                        };
                        switch (MapMode)
                        {
                            case MapMode.Default:
                                Canvas.SetLeft(rotaryTable, Convert.ToDouble(row.X) * ratio);
                                Canvas.SetTop(rotaryTable, Convert.ToDouble(row.Y) * ratio);
                                break;

                            case MapMode.Overturn:
                                Canvas.SetLeft(rotaryTable, Convert.ToDouble(row.Y) * ratio);
                                Canvas.SetTop(rotaryTable, Convert.ToDouble(row.X) * ratio);
                                break;

                            default:
                                break;
                        }
                        frame.Children.Add(rotaryTable);
                        RegisterName(frame, rotaryTable.SName, rotaryTable);
                        //frame.RegisterName($"{rotaryTable.SName}", rotaryTable);
                        rotaryTable.RotateAnimation(0, 90);
                        break;
                    //RGV
                    case "RGV":
                        RGV rgv = new RGV()
                        {
                            SName = $"{row.SName ?? "WP101"}",
                            Name = $"{row.SName ?? "WP101"}",
                            Width = Convert.ToDouble(row.Width) * ratio,
                            Height = Convert.ToDouble(row.Height) * ratio,
                            Command = FrameCommand,
                            CommandParameter = $"{controlstyle}-{row.SName ?? "WP101"}"
                        };
                        switch (MapMode)
                        {
                            case MapMode.Default:
                                Canvas.SetLeft(rgv, Convert.ToDouble(row.X) * ratio);
                                Canvas.SetTop(rgv, Convert.ToDouble(row.Y) * ratio);
                                break;

                            case MapMode.Overturn:
                                Canvas.SetLeft(rgv, Convert.ToDouble(row.Y) * ratio);
                                Canvas.SetTop(rgv, Convert.ToDouble(row.X) * ratio);
                                break;

                            default:
                                break;
                        }
                        frame.Children.Add(rgv);
                        RegisterName(frame, rgv.SName, rgv);
                        //frame.RegisterName($"{rgv.SName}", rgv);

                        break;

                    case "Stacker":
                        Stacker stacker = new Stacker()
                        {
                            SName = $"{row.SName ?? "WP101"}",
                            Name = $"{row.SName ?? "WP101"}",
                            Width = Convert.ToDouble(row.Width) * ratio,
                            Height = Convert.ToDouble(row.Height) * ratio,
                            Command = FrameCommand,
                            CommandParameter = $"{controlstyle}-{row.SName ?? "WP101"}"
                        };
                        switch (MapMode)
                        {
                            case MapMode.Default:
                                Canvas.SetLeft(stacker, Convert.ToDouble(row.X) * ratio);
                                Canvas.SetTop(stacker, Convert.ToDouble(row.Y) * ratio);
                                break;

                            case MapMode.Overturn:
                                Canvas.SetLeft(stacker, Convert.ToDouble(row.Y) * ratio);
                                Canvas.SetTop(stacker, Convert.ToDouble(row.X) * ratio);
                                break;

                            default:
                                break;
                        }
                        frame.Children.Add(stacker);
                        RegisterName(frame, stacker.SName, stacker);
                        //frame.RegisterName($"{rgv.SName}", rgv);

                        break;

                    default:
                        break;
                }
            }, DispatcherPriority.Send);
        }

        #endregion 添加元素

        GlobalControl.Frame = this.frame;

        timer = new Timer(2 * 60 * 1000); // 5分钟 = 5 * 60秒 * 1000毫秒
        timer.Elapsed += TimerElapsed;
        // 设置定时器为自动重置
        timer.AutoReset = true;
        // 先执行一次任务
        TimerElapsed(null, null);
        // 启动定时器
        timer.Start();
    }

    private async void TimerElapsed(object sender, ElapsedEventArgs e)
    {
        // 定时器触发时执行的操作
        await ConnectToHubAsync();
    }

    private async Task ConnectToHubAsync()
    {
        int retryCount = 3; // 设置重试次数
        int delayMilliseconds = 1000; // 设置每次重试之间的延迟时间，单位为毫秒

        while (retryCount > 0 && hubConnection.State != HubConnectionState.Connected)
        {
            try
            {
                await hubConnection.StartAsync();

                if (hubConnection.State == HubConnectionState.Connected)
                {
                    await InitializeControlsStatusAsync();
                }

                // 如果没有发生异常，则跳出重试循环
                break;
            }
            catch (Exception ex)
            {
                Console.WriteLine("发生异常：" + ex.Message);

                retryCount--;

                if (retryCount != 0)
                {
                    // 添加延迟，以避免频繁重试导致性能问题
                    await Task.Delay(delayMilliseconds);
                }
            }
        }
    }

    private async Task InitializeControlsStatusAsync()
    {
        List<Control> children = new List<Control>(frame.Children.OfType<Control>());
        foreach (var control in children)
        {
            await hubConnection.InvokeAsync("InitalStatus", $"{control.Name}");
        }
    }

    public static void RegisterName<T>(Canvas frame, string name, T obj) where T : FrameworkElement
    {
        // 判断指定名字是否已经被注册
        if (frame != null && frame.FindName(name) != null)
        {
            // 名字已经被注册,则注销
            frame.UnregisterName(name);
        }

        // 注册新对象
        frame.RegisterName(name, obj);
    }

    #endregion Method
}

public enum FixedSideEnum
{
    Height, Width
}

public enum MapMode
{
    Default, Overturn
}

[Serializable, XmlType("frame")]
public class Frame_Config
{
    [XmlAttribute("width")]
    public string width { get; set; }

    [XmlAttribute("height")]
    public string height { get; set; }

    public List<CanvasElement_Config> items { get; set; }
}

[Serializable, XmlType("item")]
public class CanvasElement_Config
{
    [XmlAttribute("name")]
    public string name { get; set; }

    /// <summary>
    /// 控件类型
    /// </summary>
    [XmlAttribute("controltype")]
    public string controltype { get; set; }

    [XmlAttribute("x")]
    public string x { get; set; }

    [XmlAttribute("y")]
    public string y { get; set; }

    [XmlAttribute("width")]
    public string width { get; set; }

    [XmlAttribute("height")]
    public string height { get; set; }

    [XmlAttribute("image")]
    public string image { get; set; }
}